#!/usr/bin/env python
# -*- coding: utf-8 -*- 
############################################################################
#    Copyright (C) 2007-2008
#                  Ferraro Luciano (aka lux) <luciano.ferraro@gmail.com>
#
#    This program is free software; you can redistribute it and/or modify 
#    it under the terms of the GNU General Public License as published by 
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the
#    Free Software Foundation, Inc.,
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
############################################################################

import sys
import os
import platform

system = platform.system()
#if system == "Windows":
#    import interfaces.win32api_main as interface
    
#elif system == "Linux":
import interfaces.gtk.window as interface
interface = interface.Window()
from twisted.internet import gtk2reactor
gtk2reactor.install()

from twisted.words.protocols import irc
from twisted.internet import reactor, protocol

from channels import Channels

__version__ = "0.05"
#__delay__ = 0.1
#Successivamente faro' conf.py che aprira' interfaces/*_serverslist.py in caso non
# sia settato un server predifinito, o che ridara' le conf del file di configurazione
# se ne e' stato settato uno
class conf:
    servers_names = ("irc.azzurra.org", "irc.freenode.org")
    servers_ports = {"irc.azzurra.org":6667, "irc.freenode.org":6667}
    servers_channels = {"irc.azzurra.org":["#cazzo"], "irc.freenode.org":["#rebelcodedgsa"]}
    nickname ={"irc.azzurra.org":"luxolo", "irc.freenode.org":"luxolo"}
    realnames ={"irc.azzurra.org":"luxolo", "irc.freenode.org":"luxolo"}
    usernames ={"irc.azzurra.org":"luxolo", "irc.freenode.org":"luxolo"}

conf = conf()

class Core(irc.IRCClient):
    versionName = "Merdim Chat CLIENT"
    versionNum = __version__
    versionEnv = "http://code.google.com/p/merdim/"
    #lineRate = __delay__

    def __init__(self, factory):
        self.server_name = factory.server_name
        self.server_port = factory.server_port
        self.nickname = conf.nickname[self.server_name]
        self.realnames = conf.realnames[self.server_name]
        self.usernames = conf.usernames[self.server_name]

    def connectionMade(self):
        self.handler_box = {}
        self.factory.irc = self
        self.factory.quit = self.disconnect
        self.channels = self.factory.channels
        irc.IRCClient.connectionMade(self)
        text = "Connecting to %s port %s..." % (self.server_name, self.server_port)
        interface.insert_text(text, self.server_name, style="core")

    def connectionLost(self, reason):
        irc.IRCClient.connectionLost(self, reason)
        interface.insert_text("Disconnected (%s)" % reason, self.server_name, style="core")

    """ roba di openbot, potrebbe aiutare!
    def call(self, event, function):
        if getattr(self, event) != None:
            if self.handler_box.has_key(event):
                self.handler_box[event].append(function)
            else:
                self.handler_box[event] = [function]

    def connect(self, event, args=None):
        if self.handler_box.has_key(event):
            for function in self.handler_box[event]:
                if (args != None) and (type(args) is tuple):
                    function(*args)
                elif (args != None) and (type(args) is str):
                    function(args)
                else:
                    function()
    """

    def disconnect(self, reason="Requested"):
        """Start when you get disconnected from the IRC Server
        """
        self.factory.disconnected = True
        self.quit(reason)
        #DA FARE

    def privmsg(self, user, channel, message):
        """Called when I have a message from a user to me or a channel.
        """
        user = user.split("!")
        #host = user[1]
        user = user[0]
        if (user == conf.nickname[self.server_name]) or (user == ""):
            return False
        if channel == conf.nickname[self.server_name]:
            interface.add_subtree(self.server_name, user)
            interface.insert_text(message, self.server_name, user, user, style="privmsg")
        else:
            interface.insert_text(message, self.server_name, channel, user, style="chanmsg")

    def joined(self, channel):
        """Called when I finish joining a channel.

        channel has the starting character (# or &) intact.
        """
        self.channels.add_channel(channel)
        interface.add_subtree(self.server_name, channel)
        interface.insert_text("Now talking on "+channel, self.server_name, channel, style="irc")

    def left(self, channel):
        """Called when I have left a channel.

        channel has the starting character (# or &) intact.
        """
        #channel = channel.split("#")[1]
        interface.remove_subtree(self.server_name, channel)
        self.channels.remove_channel(channel)

    def noticed(self, user, channel, message):
        """Called when I have a notice from a user to me or a channel.

        By default, this is equivalent to IRCClient.privmsg, but if your
        client makes any automated replies, you must override this!
        From the RFC::

            The difference between NOTICE and PRIVMSG is that
            automatic replies MUST NEVER be sent in response to a
            NOTICE message. [...] The object of this rule is to avoid
            loops between clients automatically sending something in
            response to something it received.
        """
        user = user.split("!")
        #host = user[1]
        user = user[0]
        interface.insert_text("-%s-" % message, usertext="-%s-" % user, style="notice")
        #DA MODIFICARE

    def modeChanged(self, user, channel, set, modes, args):
        """Called when a channel's modes are changed

        @type user: C{str}
        @param user: The user and hostmask which instigated this change.

        @type channel: C{str}
        @param channel: The channel for which the modes are changing.

        @type set: C{bool} or C{int}
        @param set: true if the mode is being added, false if it is being
        removed.

        @type modes: C{str}
        @param modes: The mode or modes which are being changed.

        @type args: C{tuple}
        @param args: Any additional information required for the mode
        change.
        """
        try:
            changed_to = args[0]
            nick = user
            for mode in modes:
                args = (channel, changed_to, mode)
                if set:
                    self.channels.set_mode(*args)
                else:
                    self.channels.clear_mode(*args)
        except:
            pass
        if modes == "o": text = "channel operator"
        elif modes == "h": text = "channel half-operator"
        elif modes == "v": text = "voice"
        else: return None
        if set: text = "%s gives %s status to %s" % (user, text, args[2])
        else: text = "%s removes %s status to %s" % (user, text, args[2])
        #DA IMPLEMENTARE I CAMBI DI MODE DEL CHANNEL IN SE STESSO
        #DA IMPLEMENTARE NELLA USERSLIST

    def pong(self, user, secs):
        """Called with the results of a CTCP PING query.
        """
        interface.insert_text("Ping, PONG (%s) - by %s" % (str(secs), user), style="irc")
        #Aggiungere un notify all'user in futuro..

    def signedOn(self):
        """Called after sucessfully signing on to the server.
        """
        ##
        #self.factory.start()
        ##
        #if conf.ns_password != None:
        #    self.msg("NickServ", "identify " + self.conf.ns_password)
        interface.insert_text("Connected. Now logging in...", self.server_name, style="core")
        
    def kickedFrom(self, channel, kicker, message):
        """Called when I am kicked from a channel.
        """
        self.channels.remove_channel(channel)
        text = "You have been kicked from %s by %s (%s)" % (channel, kicker, message)
        interface.insert_text(text, self.server_name, channel, style="irc")
        interface.remove_subtree(self.server_name, channel)

    def nickChanged(self, nick):
        """Called when my nick has been changed.
        """
        my_channels = self.channels.get_users_channels(conf.nickname[self.server_name])
        self.channels.change_nick(conf.nickname[self.server_name], nick)
        text = "You are now know as %s" % nick
        for channel in my_channels:
            interface.insert_text(text, self.server_name, channel, style="irc")
            interface.remove_user(conf.nickname[self.server_name], self.server_name, channel)
            interface.add_user(nick, self.server_name, channel)
        conf.nickname[self.server_name] = nick

    ### Things I observe other people doing in a channel.

    def userJoined(self, user, channel):
        """Called when I see another user joining a channel.
        """
        self.channels.add_user(channel, user)
        text = "%s has joined %s" % (user, channel)
        interface.insert_text(text, self.server_name, channel, style="irc")
        interface.add_user(user, self.server_name, channel)

    def userLeft(self, user, channel):
        """Called when I see another user leaving a channel.
        """
        self.channels.remove_user(channel, user)
        text = "%s has left %s" % (user, channel)
        interface.insert_text(text, self.server_name, channel, style="irc")
        interface.remove_user(user, self.server_name, channel)

    def userQuit(self, user, quitMessage):
        """Called when I see another user disconnect from the network.
        """
        users_channels = self.channels.get_users_channels(user)
        self.channels.remove_user(".all.", user)
        text = "%s has quit (%s)" % (user, quitMessage)
        for channel in users_channels:
            interface.insert_text(text, self.server_name, channel, style="irc")
            interface.remove_user(user, self.server_name, channel)

    def userKicked(self, kickee, channel, kicker, message):
        """Called when I observe someone else being kicked from a channel.
        """
        self.channels.remove_user(channel, kickee)
        text = "%s has been kicked from %s by %s (%s)" % (
            kickee, channel, kicker, message)
        interface.insert_text(text, self.server_name, channel, style="irc")
        interface.remove_user(kickee, self.server_name, channel)

    def action(self, user, channel, data):
        """Called when I see a user perform an ACTION on a channel.
        """
        user = user.split("!")
        #host = user[1]
        user = user[0]
        interface.insert_text("%s %s" % (user, data), self.server_name, channel, style="chanaction")

    def topicUpdated(self, user, channel, newTopic):
        """In channel, user changed the topic to newTopic.

        Also called when first joining a channel.
        """
        text = "Topic for %s is: %s\nTopic for %s set by %s" % (channel, newTopic, channel, user)
        interface.insert_text(text, self.server_name, channel, style="irc")

    def userRenamed(self, oldname, newname):
        """An user changed his name from oldname to newname.
        """
        users_channels = self.channels.get_users_channels(oldname)
        self.channels.change_nick(oldname, newname)
        if oldname in (conf.nickname[self.server_name], "irc_", "irc"):
            conf.nickname[self.server_name] = newname
            text = "You're now know as "+newname
        else:
            text = "%s is now know as %s" % (oldname, newname)
        for channel in users_channels:
            interface.remove_user(oldname, self.server_name, channel)
            interface.add_user(newname, self.server_name, channel)
            interface.insert_text(text, self.server_name, channel, style="irc")

    def irc_RPL_NAMREPLY(self, prefix, params):
        """Collect usernames from this channel.
        """
        channel = params[2]
        for name in params[3].split():
            # Remove operator, half-operator and voice prefixes
            if name[0] in ("@", "%", "+"):
                mode = name[0].replace("@", "o").replace("%", "h").replace("+", "v")
                self.channels.set_mode(channel, name, mode)
                name = name[1:]
            parsed_name = name
            #in futuro si aggiungeranno delle immagini nella userlist
            self.channels.add_user(channel, parsed_name)
            interface.add_user(parsed_name, self.server_name, channel)

    ### Information from the server.

    def receivedMOTD(self, motd):
        """I received a message-of-the-day banner from the server.

        motd is a list of strings, where each string was sent as a seperate
        message from the server. To display, you might want to use::

            string.join(motd, '\\n')

        to get a nicely formatted string.
        """
        interface.insert_text("\n".join(motd), self.server_name, style="motd")
        for channel in conf.servers_channels[self.server_name]:
            self.join(channel)

class Merdim(protocol.ClientFactory):
    " Start the Client, load the config file, start the plugins, etc."
    protocol = Core
    reactor = reactor

    def __init__(self, server_name):
        #self.server_number = server_number
        self.server_name = server_name
        self.server_port = conf.servers_ports[self.server_name]
        interface.add_tree(self.server_name)
        self.channels = Channels()
        #self.delay = __delay__
        self.version = __version__
        self.ENCODING = "utf-8"
        self.chan = []
        self.startdir = os.getcwd()
        self.disconnected = False
        os.chdir(self.startdir)

    def buildProtocol(self, addr):
        protocol = self.protocol(self)
        protocol.factory = self
        return protocol

    def privmsg(self, channel, message):
        if channel.startswith("#"):
            interface.insert_text(
                message, self.server_name, channel, 
                conf.nickname[self.server_name], style="self"
                )
        self.irc.msg(channel, message)

    def clientConnectionLost(self, connector, reason):
        """If we get disconnected, reconnect to server."""
        if not self.disconnected:
            interface.insert_text(
                "Re-Connecting to %s port %s..." % (self.server_name, self.server_port), 
                self.server_name)
            connector.connect()
        else:
            reactor.stop()

    def clientConnectionFailed(self, connector, reason):
        interface.insert_text(
            "Connection Failed (Unable to connect)..", self.server_name, style="core")
        #reactor.stop()

    def connect(self):
        """ Connect to the IRC Server
        """
        reactor.connectTCP(
        self.server_name, self.server_port, self)
        #reactor.run()

clients = {}
interface.start()
for server in conf.servers_names:
    clients[server] = Merdim(server)
    clients[server].connect()

interface.conf = conf
interface.clients = clients

reactor.run()
